﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Wicture.DbRESTFul;
using Wicture.DbRESTFul.Gateway;
using Wicture.DbRESTFul.SQL;
using Wicture.EPC.OnlineQueryProxy.Core;
using Wicture.EPC.OnlineQueryProxy.Models;
using Wicture.EPC.OnlineQueryProxy.Models.Business.BMW;
using Wicture.EPC.OnlineQueryProxy.Models.Business.ES;
using Wicture.EPC.OnlineQueryProxy.Services;
using Wicture.EPC.OnlineQueryProxy.Services.ES;

namespace Wicture.EPC.OnlineQueryProxy.Processors
{
    public class BmwPartPriceAndStockProcessor : PartPriceAndStockProccessor
    {
        public override List<string> BrandCodes => new List<string> { "bmw", "mini", "rolls_royce", "zinoro" };

        public override string ProcessorName => "BMWPriceQueryProcessor";

        public override QueryProcessorTask Task => QueryProcessorTask.PartPriceAndStock;

        public override object ProcessQueryResponse(QueryResponse response)
        {
            LoggerManager.Logger.LogInformation($"Query for {Task.ToString()}: {response.Params}.");
            HandleResult(response);

            return response;
        }

        async Task HandleResult(QueryResponse response)
        {
            if (response != null && !response.HasError && response.Data != null)
            {
                LoggerManager.Logger.LogInformation("BmwPartPriceAndStockProcessor.HandleResult 开始");

                try
                {
                    string brandCode = ((JObject)response.Params)["brand"].ToObject<string>();
                    BmwStockRes res = ((JObject)response.Data).ToObject<BmwStockRes>();
                    res.brandCode = brandCode;

                    //1. 写es
                    var esTask = SaveToES(res);
                    //2. 写es middle库
                    var esDbTask = SaveToMiddle(res);

                    //3. 写epc库
                    var epcTask = SaveToEpc(res);

                    await System.Threading.Tasks.Task.WhenAll(esTask, esDbTask, epcTask);
                }
                catch (Exception ex)
                {
                    LoggerManager.Logger.LogError(ex, "BmwPartPriceAndStockProcessor.HandleResult");
                }
                LoggerManager.Logger.LogInformation("BmwPartPriceAndStockProcessor.HandleResult 结束");
            }
        }

        async Task SaveToEpc(BmwStockRes info)
        {
            try
            {
                LoggerManager.Logger.LogInformation("BmwPartPriceAndStockProcessor.SaveToEpc 开始");

                if (info != null)
                {
                    BmwStockInfo param = GetStockInfo(info);
                    List<string> connList = base.GetEpcSyncDbConns(info.brandCode);
                    if (connList != null && connList.Any())
                    {
                        foreach (var conn in connList)
                        {
                            SqlConnectionManager sqlConnectionManager = new SqlConnectionManager() { ReadConnectionString = conn, WriteConnectionString = conn };
                            DbRESTFulRepository repository = new DbRESTFulRepository(sqlConnectionManager);
                            repository.Invoke(CSIs.Update_Epc_PartPriceStock, param);
                        }
                    }
                }
                LoggerManager.Logger.LogInformation("BmwPartPriceAndStockProcessor.SaveToEpc 成功");
            }
            catch (Exception ex)
            {
                LoggerManager.Logger.LogError(ex, "BmwPartPriceAndStockProcessor.SaveToEpc");
            }
            finally
            {
                LoggerManager.Logger.LogInformation("BmwPartPriceAndStockProcessor.SaveToEpc 结束");
            }
        }
        async Task SaveToMiddle(BmwStockRes info)
        {
            try
            {
                LoggerManager.Logger.LogInformation("BmwPartPriceAndStockProcessor.SaveToMiddle 开始");

                if (info != null)
                {
                    BmwStockInfo param = GetStockInfo(info);
                    List<string> connList = base.GetEsSyncDbConns(info.brandCode);
                    if (connList != null && connList.Any())
                    {
                        foreach (var conn in connList)
                        {
                            SqlConnectionManager sqlConnectionManager = new SqlConnectionManager() { ReadConnectionString = conn, WriteConnectionString = conn };
                            DbRESTFulRepository repository = new DbRESTFulRepository(sqlConnectionManager);

                            string tableName = $"part_es_{info.brandCode}".ToLower();
                            param.tableName = tableName;
                            repository.Invoke(CSIs.Update_Es_PartPriceStock_For_Bmws, param);
                        }
                    }
                }
                LoggerManager.Logger.LogInformation("BmwPartPriceAndStockProcessor.SaveToMiddle 成功");
            }
            catch (Exception ex)
            {
                LoggerManager.Logger.LogError(ex, "BmwPartPriceAndStockProcessor.SaveToMiddle");
            }
            finally
            {
                LoggerManager.Logger.LogInformation("BmwPartPriceAndStockProcessor.SaveToMiddle 结束");
            }
        }

        async Task SaveToES(BmwStockRes info)
        {
            try
            {
                LoggerManager.Logger.LogInformation("BmwPartPriceAndStockProcessor.SaveToES 开始");

                if (info != null)
                {
                    BmwStockInfo param = GetStockInfo(info);

                    PartEsService esService = new PartEsService(new ESSearchService());
                    var partList = esService.PartsSearch(param);
                    if (partList != null && partList.Any())
                    {
                        partList.ForEach(e => { e.priceUpdatedAt = DateTime.Now; e.price = param.price; e.cost = param.cost; e.stock = param.stock; e.stockInfos = param.stockInfos; });

                        await esService.IndexBulk<ESPartInfo>(partList);
                    }
                }
                LoggerManager.Logger.LogInformation("BmwPartPriceAndStockProcessor.SaveToES 成功");
            }
            catch (Exception ex)
            {
                LoggerManager.Logger.LogError(ex, "BmwPartPriceAndStockProcessor.SaveToES");
            }
            finally
            {
                LoggerManager.Logger.LogInformation("BmwPartPriceAndStockProcessor.SaveToES 结束");
            }
        }


        private static IDictionary<string, string> cityDic = new Dictionary<string, string> {
            { "库房  SY01", "北京" },
            { "库房  SY02", "上海"},
            { "库房  SY03", "佛山"},
            { "库房  SY06", "成都"},
            { "库房  SY07", "沈阳"}
        };
        BmwStockInfo GetStockInfo(BmwStockRes info)
        {
            decimal taxRate = AppConfig.TaxRate;
            decimal price = 0, cost = 0;
            int stock = 0;
            string stockInfo = string.Empty;
            if (info.prices != null && info.prices.Any())
            {
                foreach (var item in info.prices)
                {
                    if (item.type == "sale")
                    {
                        price = item.price > 0 ? item.price * taxRate : item.price;
                    }
                    else if (item.type == "cost")
                    {
                        cost = item.price > 0 ? item.price * taxRate : item.price;
                    }
                }
            }
            if (info.stocks != null && info.stocks.Any())
            {
                stock = info.stocks.Sum(e => e.stock);
                info.stocks.ForEach(e =>
                {
                    if (cityDic.ContainsKey(e.warehouse))
                    {
                        e.city = cityDic[e.warehouse];
                    }
                });
                stockInfo = JsonConvert.SerializeObject(info.stocks);
            }
            return new BmwStockInfo { brandCode = info.brandCode, partCode = info.partCode, price = price, cost = cost, stock = stock, stockInfos = stockInfo };
        }
    }
}
